#include "EventHandlers.h"
#include "CommonFunctions.h"
#include <stdio.h>
#include <string.h>

/*
 * Spracuje zvukovu informaciu, metoda pre hraca
 */
void EventHandlers::OnHear(int time, float direction, bool ourTeam, int uniform, const char* msg)
{
	// Ignoruj spravy z druheho timu
	if(!ourTeam)
		return;

#ifdef GOALIE
	// Ignoruj tiez, prilis kratke spravy
	if(strlen(msg) != 10)
		return;
#else
	// Spracovanie loptosskych sprav
	if (strlen(msg) >= 2 && msg[0] == 'L')
	{
		char sprava[100];
		strcpy(sprava, msg);
		sprava[strlen(sprava)-1] = '\0'; //odstranenie zatvorky ')'
		GetLeadershipBehaviour()->ProcessLeaderMSG(time, uniform, sprava);
		return;
	}
#endif

	// Zisti informacie o odosielatelovi
	Player player(world);
	player.SetUniform(uniform);

	// Parsujeme jeho spravu. Kazdy znak je skonvertovany na cislo z intervalu <0, 71> (ignorujeme '_' a ' ').
	// Cislo je rozdelene do troch casti: 2x 3-stavove a 3x 2-stavove (3*3*2*2*2=72)
	// Pouzivame tri casti a interval <0, 71> cisiel na ulozenie udajov efektivnym sposobom.
	// Pozri aj PlayerSkills:SendInfo()

	unsigned char parts[10][6];
	for(int i = 0; i < 10; i++)
	{
		// Konvertuje do <0, 71>
		unsigned char num;
		if((msg[i] >= 'a') && (msg[i] <= 'z'))
			num = ((char) msg[i]) - 'a';
		else if((msg[i] >= 'A') && (msg[i] <= 'Z'))
			num = ((char) msg[i]) - 'A' + 26;
		else if((msg[i] >= '0') && (msg[i] <= '9'))
			num = ((char) msg[i]) - '0' + 52;
		else if(msg[i] == '+')
			num = 62;
		else if(msg[i] == '-')
			num = 63;
		else if(msg[i] == '*')
			num = 64;
		else if(msg[i] == '/')
			num = 65;
		else if(msg[i] == '(')
			num = 66;
		else if(msg[i] == ')')
			num = 67;
		else if(msg[i] == '.')
			num = 68;
		else if(msg[i] == '?')
			num = 69;
		else if(msg[i] == '<')
			num = 70;
		else if(msg[i] == '>')
			num = 71;
		else
		{
			WARNN("failed decoding for hear (%i->%c)", i, msg[i]);
			return;
		}

		// Rozdelene do casti
		parts[i][0] = num;
		parts[i][1] = num % 3; num /= 3;
		parts[i][2] = num % 3; num /= 3;
		parts[i][3] = num % 2; num /= 2;
		parts[i][4] = num % 2; num /= 2;
		parts[i][5] = num % 2; num /= 2;
	}

	Point* flags = world->params->flags;

	/*	DBGN("---");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][0]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][1]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][2]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][3]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][4]); DBGN("");
	for(i = 0; i < 10; i++) DBG("%i ", (int) parts[i][5]); DBGN("");
	*/

	// Alokacia casti:
	// - = volne, X = hracova x-ova suradnica, Y = hracova y-ova suradnica
	// D = hracov smer, S = hracova rychlost
	// 1(3) XYDS----YY
	// 2(3) XYDS----DX
	// 3(2) XYDS----DX
	// 4(2) XYDS----SX
	// 5(2) XYDS----YX
	// This has to be the same as in SendInfo().

	// X suradnica hraca (pouziva sa 72,3,2,2,2 pozri hore)
	int tmp = (((parts[0][0] * 3 + parts[9][2]) * 2 + parts[9][3]) * 2 + parts[9][4]) * 2 + parts[9][5];
	//	DBGN("tmp_x %i", tmp);
	player.pos.SetX(float(tmp) * (flags[R0].GetX() - flags[L0].GetX()) / 
		float(72 * 3 * 2 * 2 * 2) + flags[L0].GetX());

	// Y suradnica hraca (pouziva sa 72,3,3,2 pozri hore)
	tmp = ((parts[1][0] * 3 + parts[9][1]) * 3 + parts[8][1]) * 2 + parts[8][5];
	//	DBGN("tmp_y %i", tmp);
	player.pos.SetY(float(tmp) * (flags[B0].GetY() - flags[T0].GetY()) / 
		float(72 * 3 * 3 * 2) + flags[T0].GetY());

	// Smer hraca (pouziva sa 72,3,2 pozri hore)
	tmp = (parts[2][0] * 3 + parts[8][2]) * 2 + parts[8][3];
	float dir = float(tmp) * 2.0f * M_PI / float(72 * 3 * 2);
	//	DBGN("tmp_dir %i ang %0.3f", tmp, dir);

	// Rychlost hraca (pouziva sa 72,2 pozri hore)
	tmp = parts[3][0] * 2 + parts[8][4];
	//	DBGN("tmp_spd %i", tmp);
	float spd = float(tmp) * (world->params->server->player_speed_max + world->params->player->player_speed_max_delta_max) / float(72 * 2);

	player.vel.SetX(float(spd * cos(dir)));
	player.vel.SetY(float(spd * sin(dir)));
	player.SetAge(MAX_PLAYER_AGE - 10);

	// Uloz informaciu o odosielatelovi
	int index = world->FindFriendIndex(player.GetUniform());

	if(index == -1)
		world->friends.Add(player);
	else
		world->friends[index] = player;

	SHOUT_DBGN("SHT %i: RECV INFO: %i: %0.2f, %0.2f, %0.2f, %0.2f", world->state->GetSimTime(), player.GetUniform(), player.pos.GetX(), player.pos.GetY(), player.vel.GetX(), player.vel.GetY());
	if(index == -1) SHOUT_DBGN("SHT %i: Hmmm, new player", world->state->GetSimTime());

	//	&other_ball.pos.GetX(), &other_ball.pos.GetY(), &other_ball.vel.GetX(), &other_ball.vel.GetY(), &other_ball.age,

	/*	if(ball.valid) //viem o lopte, takze mozem upravit poziciu
	{
	float mydist = (world->ball->pos - world->me->pos).GetLength();
	float hisdist = (other_ball.pos - other_player.pos).GetLength();

	if(hisdist < mydist && other_ball.age < ball.age) //podmienka aktualizacie
	{
	ball = other_ball;
	ball.valid = true;
	}
	}*/
}

// Inicializovanie taktickeho modulu
void EventHandlers::OnInit(RealSide realSide, unsigned uniform, PlayMode iMode)	
{
	// inicializacia formacii
	//DATA_STORAGE.formation.InitRawUnits( SIDE_LEFT, PlayerConfig.GetFormation(), PlayerConfig.GetDefUnit(), 
//	PlayerConfig.GetMidUnit(), PlayerConfig.GetForUnit() );
//	DATA_STORAGE.formation.InitRawUnits( SIDE_LEFT, FORMATION_343, UNIT_3_L, UNIT_4_OV, UNIT_3_OV );
//	DATA_STORAGE.formation.InitRawUnits(SIDE_LEFT, -1, 16, 2, 17);
//	DATA_STORAGE.formation.SetUnitOffset(-30.0f);
	FILE *f;
	char def, mid, atk, offset;
	float offset2;

	if ((f = fopen("formation.cfg", "r")) != NULL)
	{
		if (4 != fscanf(f, "%c%c%c%c", &def, &mid, &atk, &offset))
		{
			TXT("Zly format configu formacii, pouzivam default QCRN\n\n");
			DATA_STORAGE.formation.SetUnits(16, 2, 17);
			DATA_STORAGE.formation.SetUnitOffset(-30.0);
			fclose(f);
		}
		else
		{
			TXT("Formacia nacitana: %c%c%c%c\n\n", def, mid, atk, offset);
			DATA_STORAGE.formation.SetUnits(def - 'A', mid - 'A', atk - 'A');
			offset2 = 2.0f*(offset-'A') - FIELDWIDTH/2.0f;
			DATA_STORAGE.formation.SetUnitOffset(offset2);
			fclose(f);
		}
	}
	else
	{
		TXT("Config formacii nenajdeny, pouzivam default QCRN\n\n");
		DATA_STORAGE.formation.SetUnits(16, 2, 17);	
		DATA_STORAGE.formation.SetUnitOffset(-30.0);
	}
}

/*
 * handler hracieho modu
 */
void EventHandlers::OnChangeMode(int time, PlayMode mode)
{			
	// Ak je to jeden z vykopavacich modov, tak zacni scanovanie okoliteho okolia. Pozri BehaveWithBall()
	DATA_STORAGE.scanBeforeKickOffAngle = 0;

	// Kolko cyklov uz trvaju jednotlive mody?
	DATA_STORAGE.cornerKickModeDuration = 0;
	DATA_STORAGE.freeKickModeDuration = 0;
	DATA_STORAGE.indFreeKickModeDuration = 0;
	DATA_STORAGE.kickInModeDuration = 0;
}
